package recycle.service;

import io.vertx.core.CompositeFuture;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import lombok.RequiredArgsConstructor;
import recycle.pojo.Appointment;
import recycle.pojo.Station;
import recycle.repository.AppointmentRepository;
import recycle.repository.CategoryRepository;
import recycle.repository.StationRepository;
import recycle.repository.UserRepository;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@RequiredArgsConstructor
public class AppointmentService {

    private final AppointmentRepository appointmentRepository;
    private final StationRepository stationRepository;
    private final UserRepository userRepository;
    private final CategoryRepository categoryRepository;


    public Future<Long> create(Appointment appointment) {
        appointment.setUserId(Long.valueOf(Vertx.currentContext().get("userId")));
        return appointmentRepository.createAppointmentWithTransaction(appointment);
    }

    // public Future<JsonObject> list(Appointment appointment , Integer pageNum, Integer pageSize) {
    //     return appointmentRepository.selectList( appointment , pageNum, pageSize);
    // }

    public Future<JsonObject> list(Appointment appointment, Integer pageNum, Integer pageSize) {
        // 1. 先查询分页列表
        return appointmentRepository.selectList(appointment, pageNum, pageSize)
                .compose(pagedResult -> {
                    // 2. 将JsonArray转换为List<Appointment>
                    List<Appointment> appointments = pagedResult.getJsonArray("records").getList();

                    // 3. 为每个Appointment异步加载详细信息
                    List<Future<Appointment>> detailFutures = appointments.stream()
                            .map(appt -> details(appt.getId()))
                            .collect(Collectors.toList());

                    // 4. 使用Future.sequence合并所有Future（Vert.x 4特性）
                    return sequence(detailFutures)
                            .map(fullAppointments -> {
                                // 5. 更新分页结果中的列表
                                pagedResult.put("records", fullAppointments);
                                return pagedResult;
                            });
                });
    }

    public static <T> Future<List<T>> sequence(List<Future<T>> futures) {
        Promise<List<T>> promise = Promise.promise();

        if (futures.isEmpty()) {
            promise.complete(new ArrayList<>());
            return promise.future();
        }

        // 使用数组保持原始顺序
        @SuppressWarnings("unchecked")
        T[] results = (T[]) new Object[futures.size()];
        AtomicInteger counter = new AtomicInteger(0);

        for (int i = 0; i < futures.size(); i++) {
            final int index = i;
            futures.get(i).onComplete(ar -> {
                if (ar.succeeded()) {
                    results[index] = ar.result(); // 按原始位置存储
                    if (counter.incrementAndGet() == futures.size()) {
                        promise.complete(Arrays.asList(results));
                    }
                } else {
                    promise.fail(ar.cause());
                }
            });
        }

        return promise.future();
    }

    public Future<Appointment> details(Long id) {
        return appointmentRepository.selectById(id)
                .compose(appointment -> {
                    // 先查 Station
                    return stationRepository.selectById(appointment.getStationId())
                            .compose(station -> {
                                appointment.setStation(station);
                                // 再查 User
                                return userRepository.selectById(appointment.getUserId());
                            })
                            .compose(user -> {
                                appointment.setUser(user);
                                // 最后查 Category
                                return categoryRepository.selectById(appointment.getCategoryId());
                            })
                            .map(category -> {
                                appointment.setCategory(category);
                                return appointment;
                            });
                });
    }


    public Future<Void> update(Appointment appointment) {
        return appointmentRepository.updateById(appointment);
    }

    public Future<Void> delete(Long id) {
        return appointmentRepository.deleteById(id);
    }

    public Future<List<Appointment>> listMy() {
        Long userId = Long.valueOf(Vertx.currentContext().get("userId"));
        return appointmentRepository.selectListByUserId(userId)
                .compose(appointments -> {
                    // 为每个预约加载详细信息
                    List<Future<Appointment>> detailFutures = appointments.stream()
                            .map(appt -> details(appt.getId()))
                            .collect(Collectors.toList());

                    // 使用 CompositeFuture 合并所有 Future
                    return sequence(detailFutures).map(result -> result);
                });
    }

    public Future<Void> finishById(Long id) {
        // 1. 先查询预约获取必要信息
        return appointmentRepository.selectById(id)
                .compose(appointment -> {
                    if (appointment == null) {
                        return Future.failedFuture("Appointment not found: " + id);
                    }
                    if (appointment.getStatus() == 1) {
                        return Future.failedFuture("Appointment already completed: " + id);
                    }

                    Long stationId = appointment.getStationId();
                    Integer weight = appointment.getWeight();

                    // 2. 开启事务
                    return appointmentRepository.getClient().withTransaction(conn -> {
                        // 3. 获取station并锁定（使用Repository方法）
                        return stationRepository.selectById(stationId)
                                .compose(station -> {
                                    if (station == null) {
                                        return Future.failedFuture("Station not found: " + stationId);
                                    }

                                    // 4. 转换weight（根据实际类型调整）
                                    int weightToAdd = weight;
                                    int newStorage = station.getStorage() + weightToAdd;

                                    // 5. 并行执行两个更新
                                    Appointment apt = new Appointment();
                                    apt.setId(id);
                                    apt.setStatus(1);


                                    Station sta = new Station();
                                    sta.setId(stationId);
                                    sta.setStorage(newStorage);
                                    return CompositeFuture.all(
                                            appointmentRepository.updateById(apt),
                                            stationRepository.updateById(sta)
                                    ).mapEmpty();
                                });
                    });
                })
                ;
    }
}